//! # 代码生成辅助函数

use crate::error::CliResult;
use std::collections::HashMap;
use std::path::Path;
use tokio::fs;

/// 生成服务测试
pub async fn generate_service_test(
    service_dir: &Path,
    variables: &HashMap<String, serde_json::Value>,
) -> CliResult<()> {
    let template = r#"//! # {{pascal_case_name}} 服务测试

use super::*;
use {{pascal_case_name}}Service;

#[tokio::test]
async fn test_{{snake_case_name}}_service_creation() {
    let service = {{pascal_case_name}}Service::new();
    assert!(!service.handler().is_null());
}

#[tokio::test]
async fn test_{{snake_case_name}}_crud_operations() {
    let service = {{pascal_case_name}}Service::new();
    let handler = service.handler();
    
    let mut data = std::collections::HashMap::new();
    data.insert("name".to_string(), "test".to_string());
    
    let result = handler.create(data).await;
    assert!(result.is_ok());
}
"#;

    let handlebars = handlebars::Handlebars::new();
    let rendered = handlebars.render_template(template, variables)?;
    
    let test_file = service_dir.join("tests.rs");
    fs::write(test_file, rendered).await?;
    Ok(())
}

/// 生成模型文件
pub async fn generate_model_file(
    model_file: &Path,
    variables: &HashMap<String, serde_json::Value>,
) -> CliResult<()> {
    let template = r#"//! # {{pascal_case_name}} 数据模型

use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use uuid::Uuid;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct {{pascal_case_name}} {
    pub id: Uuid,
    pub name: String,
    pub description: Option<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

impl {{pascal_case_name}} {
    pub fn new(name: String) -> Self {
        let now = Utc::now();
        Self {
            id: Uuid::new_v4(),
            name,
            description: None,
            created_at: now,
            updated_at: now,
        }
    }
}
"#;

    let handlebars = handlebars::Handlebars::new();
    let rendered = handlebars.render_template(template, variables)?;
    fs::write(model_file, rendered).await?;
    Ok(())
}

/// 生成配置文件
pub async fn generate_config_file(
    config_file: &Path,
    variables: &HashMap<String, serde_json::Value>,
) -> CliResult<()> {
    let template = r#"//! # {{pascal_case_name}} 配置

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct {{pascal_case_name}}Config {
    pub service: ServiceConfig,
    pub database: DatabaseConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServiceConfig {
    pub name: String,
    pub port: u16,
    pub host: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]  
pub struct DatabaseConfig {
    pub url: String,
    pub max_connections: u32,
}

impl Default for {{pascal_case_name}}Config {
    fn default() -> Self {
        Self {
            service: ServiceConfig {
                name: "{{snake_case_name}}".to_string(),
                port: 8080,
                host: "0.0.0.0".to_string(),
            },
            database: DatabaseConfig {
                url: "postgres://localhost/{{snake_case_name}}".to_string(),
                max_connections: 10,
            },
        }
    }
}
"#;

    let handlebars = handlebars::Handlebars::new();
    let rendered = handlebars.render_template(template, variables)?;
    fs::write(config_file, rendered).await?;
    Ok(())
}

/// 生成客户端文件
pub async fn generate_client_file(
    client_file: &Path,
    variables: &HashMap<String, serde_json::Value>,
) -> CliResult<()> {
    let template = r#"//! # {{pascal_case_name}} 客户端

use serde::{Deserialize, Serialize};
use reqwest::Client;
use url::Url;

#[derive(Debug, Clone)]
pub struct {{pascal_case_name}}Client {
    client: Client,
    base_url: Url,
}

impl {{pascal_case_name}}Client {
    pub fn new(base_url: String) -> Result<Self, Box<dyn std::error::Error>> {
        Ok(Self {
            client: Client::new(),
            base_url: Url::parse(&base_url)?,
        })
    }
    
    pub async fn create<T>(&self, data: &T) -> Result<String, Box<dyn std::error::Error>>
    where T: Serialize,
    {
        let url = self.base_url.join("/api/{{snake_case_name}}")?;
        let response = self.client.post(url).json(data).send().await?;
        Ok(response.text().await?)
    }
}
"#;

    let handlebars = handlebars::Handlebars::new();
    let rendered = handlebars.render_template(template, variables)?;
    fs::write(client_file, rendered).await?;
    Ok(())
}

/// 生成测试文件
pub async fn generate_test_file(
    test_file: &Path,
    variables: &HashMap<String, serde_json::Value>,
) -> CliResult<()> {
    let template = r#"//! # {{pascal_case_name}} 测试

#[tokio::test]
async fn test_{{snake_case_name}}_basic() {
    assert!(true);
}

#[tokio::test]
async fn test_{{snake_case_name}}_async_operations() {
    let result = async_operation().await;
    assert!(result.is_ok());
}

async fn async_operation() -> Result<String, Box<dyn std::error::Error>> {
    Ok("success".to_string())
}
"#;

    let handlebars = handlebars::Handlebars::new();
    let rendered = handlebars.render_template(template, variables)?;
    fs::write(test_file, rendered).await?;
    Ok(())
}

/// 更新模块声明
pub async fn update_module_declarations(service_name: &str) -> CliResult<()> {
    let lib_file = Path::new("src/lib.rs");
    if lib_file.exists() {
        let content = fs::read_to_string(lib_file).await.unwrap_or_default();
        if !content.contains("pub mod services") {
            let new_content = format!("{}pub mod services;\n", content);
            fs::write(lib_file, new_content).await?;
        }
    }
    Ok(())
}

/// 更新 models/mod.rs
pub async fn update_models_mod(model_name: &str) -> CliResult<()> {
    let mod_file = Path::new("src/models/mod.rs");
    let content = fs::read_to_string(mod_file).await.unwrap_or_default();
    
    if !content.contains(&format!("mod {}", model_name)) {
        let new_content = format!("{}pub mod {};\npub use {}::*;\n", content, model_name, model_name);
        fs::write(mod_file, new_content).await?;
    }
    Ok(())
}

/// 更新 config/mod.rs
pub async fn update_config_mod(config_name: &str) -> CliResult<()> {
    let mod_file = Path::new("src/config/mod.rs");
    let content = fs::read_to_string(mod_file).await.unwrap_or_default();
    
    if !content.contains(&format!("mod {}", config_name)) {
        let new_content = format!("{}pub mod {};\npub use {}::*;\n", content, config_name, config_name);
        fs::write(mod_file, new_content).await?;
    }
    Ok(())
}

/// 更新 clients/mod.rs
pub async fn update_clients_mod(client_name: &str) -> CliResult<()> {
    let mod_file = Path::new("src/clients/mod.rs");
    let content = fs::read_to_string(mod_file).await.unwrap_or_default();
    
    if !content.contains(&format!("mod {}", client_name)) {
        let new_content = format!("{}pub mod {};\npub use {}::*;\n", content, client_name, client_name);
        fs::write(mod_file, new_content).await?;
    }
    Ok(())
}